package com.amtf.datafile3.cfg.fil;

import java.io.File;
import java.text.Format;
import java.util.List;

import org.jdom.Attribute;
import org.jdom.DataConversionException;
import org.jdom.Document;
import org.jdom.Element;

import com.amtf.datafile3.DataFieldDefinition;
import com.amtf.datafile3.DataFieldType;
import com.amtf.datafile3.DataTableDefinition;
import com.amtf.datafile3.DefinitionException;
import com.amtf.datafile3.cfg.std.StdDataFieldDefinition;
import com.amtf.datafile3.cfg.std.StdDefinitionStore;
import com.amtf.datafile3.core.std.type.StringFieldType;

public class FilDataDefinitionFactory extends StdDefinitionStore<DataTableDefinition> {
	public static final FilDataDefinitionFactory config = new FilDataDefinitionFactory();

	public static DataTableDefinition parse(String defineFile) throws DefinitionException {
		return parse(new File(defineFile));
	}

	public static DataTableDefinition parse(File defineFile) throws DefinitionException {
		Document doc = loadDocument(defineFile);
		return config.parse(doc, doc.getRootElement());
	}

	public static DataTableDefinition create(String name, String charset, int startRow, boolean firstRowTitle, int[] columnsLength) {
		DataTableDefinition tabledef = new FilDataTableDefinition(name, charset, startRow, firstRowTitle);
		if (columnsLength != null) {
			int startIndex = 0, lastLength = 0;
			for (int i = 0; i < columnsLength.length; i++) {
				startIndex += lastLength;

				FilDataFieldDefinition fieldDefinition = new FilDataFieldDefinition(null, new StringFieldType(), startIndex, columnsLength[i], null, null);
				tabledef.addField(fieldDefinition);

				lastLength = columnsLength[i];
			}
		}
		return tabledef;
	}

	@Override
	protected DataTableDefinition parse(Document doc, Element root) throws DefinitionException {
		Attribute attrib = null;
		String value = null;

		Element recordDef = doc.getRootElement().getChild("table-definition");
		if (recordDef == null) {
			recordDef = doc.getRootElement().getChild("TableDefinition");
			if (recordDef == null) {
				throw new DefinitionException("Table definition not found!");
			}
		}

		String name = "";
		// char fill = ',';
		String charset = "UTF-8";
		int startRow = 1;
		boolean firstRowTitle = false;

		value = recordDef.getAttributeValue("name");
		if (value != null && !"".equals(value)) {
			name = value;
		} else {
			throw new DefinitionException("Table name is empty!");
		}

		value = recordDef.getAttributeValue("charset");
		if (value != null && !"".equals(value)) {
			charset = value;
		} else {
			// throw new DefinitionException("Charset is empty!");
		}

		value = recordDef.getAttributeValue("startRow");
		if (value != null && !"".equals(value)) {
			startRow = Integer.valueOf(value);
		} else {
			startRow = 1;
		}

		attrib = recordDef.getAttribute("firstRowTitle");
		if (attrib != null) {
			try {
				firstRowTitle = attrib.getBooleanValue();
			} catch (DataConversionException e1) {
				throw new DefinitionException("Property firstRowTitle is invalid!");
			}
		} else {
			throw new DefinitionException("Property firstRowTitle is invalid!");
		}

		// value = recordDef.getAttributeValue("fill");
		// if (value != null && !"".equals(value)) {
		// fill = value.charAt(0);
		// } else {
		// throw new DefinitionException("Property fill is empty!");
		// }

		DataTableDefinition dataRecDef = new FilDataTableDefinition(name, charset, startRow, firstRowTitle);

		int startIndex = 0, lastLength = 0;
		int index = 0;
		List<Element> es = recordDef.getChildren();
		for (Element e : es) {
			DataFieldType fieldType = null;

			boolean allowEmpty = true;
			String defaultValue = null;
			String outformatstr = null;
			String informatstr = null;
			int length = 0;

			if (e.getName().toLowerCase().contains("column")) {
				index++;

				name = e.getAttributeValue("name");
				if (name == null || name.length() == 0) {
					name = "Column" + index;
				}

				try {
					attrib = e.getAttribute("length");
					if (attrib == null) {
						length = -1;
					} else {
						length = attrib.getIntValue();
					}
				} catch (DataConversionException e1) {
					throw new DefinitionException(e1);
				}

				try {
					allowEmpty = e.getAttribute("allowEmpty").getBooleanValue();
				} catch (DataConversionException e1) {
					throw new DefinitionException(e1);
				}

				try {
					outformatstr = e.getAttribute("outFormat").getValue();
				} catch (Throwable e1) {
					outformatstr = null;
				}

				try {
					informatstr = e.getAttribute("inFormat").getValue();
				} catch (Throwable e1) {
					informatstr = null;
				}

				try {
					defaultValue = e.getAttribute("defaultValue").getValue();
				} catch (Throwable e1) {
					defaultValue = null;
				}

				String valueTypeName = e.getAttribute("type").getValue();// .toLowerCase();
				fieldType = createFieldType(valueTypeName, allowEmpty, defaultValue, informatstr, outformatstr);
				Format[] fmts = createInOutFormat(fieldType, informatstr, outformatstr);

				if (length < 0) {
					length = fieldType.getTotalLength();
				}

				startIndex += lastLength;

				StdDataFieldDefinition fieldDef = new FilDataFieldDefinition(name, fieldType, startIndex, length, fmts[0], fmts[1]);
				dataRecDef.addField(fieldDef);

				lastLength = length;
			}
		}

		return dataRecDef;
	}

}
